package parser;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.StringReader;
import java.util.Iterator;
import java.util.Map.Entry;

import org.jrubyparser.CompatVersion;
import org.jrubyparser.Parser;
import org.jrubyparser.ast.Node;
import org.jrubyparser.parser.ParserConfiguration;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.safety.Whitelist;

public class MainBuilder {
	private static String rootDir;
	private static Storage storage;

	public static void main(String[] args) throws FileNotFoundException {
        rootDir = "E:/KULIYAH/SEMESTER VIII/Cin[TA]/program/sample_app_rails_4-master";
        storage = Storage.getInstance();
        
        File dirModel = new File (rootDir+"/app/models"); 
        File dirView = new File (rootDir+"/app/views"); 
        File dirController = new File (rootDir+"/app/controllers");
        File rootController = new File(rootDir+"/config/routes.rb");
		String code;
		code = readLine(rootController);
		//Node ast=parsingRuby(code);
		visitRoot(parsingRuby(code));
        readingFiles("model", dirModel);
        readingFiles("view", dirView);
        readingFiles("controller", dirController);
        buildCFG();
    }
	
	public static void visitRoot(Node ast)
	{
		RoutesVisitor visitor = new RoutesVisitor();
		ast.accept(visitor);
	}
	
	public static void visitRuby(Node ast, String key)
	{
		StatementVisitor visitor = new StatementVisitor();
		visitor.setKey(key);
		ast.accept(visitor);
	}
	
	public static void buildCFG()
	{
		Iterator<String> iter = storage.getProgramAST().keySet().iterator();
		while(iter.hasNext())
		{
			String key = iter.next();
			Node ast = storage.getProgramAST().get(key);
			visitRuby(ast, key);
		}
		System.out.println("Jumlah CFG: "+storage.getCfgFile().size());
		for(Entry<String, ControlFlowGraph> n: storage.getCfgFile().entrySet())
		{
			System.out.println("CFG dari:"+n.getKey());
			System.out.println("block: "+n.getValue().getGraphNodes().size());
			for(CFGNode node: n.getValue().getGraphNodes())
			{
				//System.out.println(node.getClassName()+";"+node.getMethodName());
				for(CFGNode coming : node.getComingNodes())
				{
					System.out.println("incoming nodes:\n\t"+coming.getCode());
				}
				System.out.println("+++++++++++++++++++++++");
				System.out.println(node.getCode());
				System.out.println("+++++++++++++++++++++++");
				System.out.println("("+node.getType()+")");
				for(CFGNode out : node.getOutgoingNodes())
				{
					System.out.println("outgoing nodes:\n\t"+out.getCode());
				}
				System.out.println("-----------------------------------------------------");
			}
			System.out.println("****************");
		}
		
		/*checkingMethod();
		System.out.println("jumlah method:"+storage.getMethodList().size()+"\nList of Method:");
		for(Entry<String, List<Method>> n: storage.getMethodList().entrySet())
		{
			for(Method method: n.getValue())
			{
				System.out.println(n.getKey()+":"+method.getName());
			}
		}*/
	}
	
	public static void readingFiles(String key, File dir){ 
        File[] files = dir.listFiles(); 
        String sourceCode;
        for (int i = 0; i < files.length; i++) {  
            String fileName = files[i].getName(); 
            if (fileName.endsWith(".rb")||fileName.endsWith("html.erb")) { 
                if (files[i].isFile()) {  
                	Node ASTNode=null;
                	try {
						sourceCode = readLine(new File(files[i].getPath()));
	        			//System.out.println(sourceCode+"\n");
	        			if(key.equals("model"))
	        			{
		        			ASTNode = parsingRuby(sourceCode);
	        				storage.addModelsFile(fileName, sourceCode);
	        				storage.addProgramAST(fileName+";model", ASTNode);
	        			}
	        			if(key.equals("view"))
	        			{
		        			//parsingHTML(sourceCode, fileName);
	        				storage.addViewsFile(fileName, sourceCode);
	        				//storage.addProgramAST(fileName+";view", ASTNode);
	        			}
	        			if(key.equals("controller"))
	        			{
		        			ASTNode = parsingRuby(sourceCode);
	        				storage.addControllersFile(fileName, sourceCode);
	        				storage.addProgramAST(fileName+";controller", ASTNode);
	        			}
	        			
					} catch (FileNotFoundException e) {
						e.printStackTrace();
					}
                } 
            } 
            if (files[i].isDirectory()) {  
                readingFiles(key, files[i]);  
            }
        }
    }
	
	public static String readLine(File file) throws FileNotFoundException
	{
		String line="";
		FileInputStream fis = new FileInputStream(file);
		try {
			int counter;
            counter = fis.read();
            line += (char)counter;
            while((counter=fis.read()) != -1)
            {
                line+=(char)counter;
            }
    		fis.close();
    		return line;
		} catch (IOException e) {
			e.printStackTrace();
		}
		return line;
	}
	
	public static Node parsingRuby(String code)
	{
		Parser rubyParser = new Parser();
        StringReader in = new StringReader(code);
        CompatVersion version = CompatVersion.RUBY2_0;
        ParserConfiguration config = new ParserConfiguration(0, version);
        return rubyParser.parse("<code>", in, config);
    }
	
	public static void parsingHTML(String code, String fileName)
	{
		Document doc;
		try{
			code = Jsoup.clean(code, Whitelist.basic());
			doc = Jsoup.parse(code);

			Element body = doc.body();
			HtmlVisitor visitor=new HtmlVisitor();
			visitor.setNameFile(fileName);
			body.traverse(visitor);

			/*
			Elements links = doc.select("a[href]"); 
			Elements forms = doc.select("form");
			for(Element link:links)
			{
				System.out.println("\nlink : " + link.attr("href"));
				System.out.println("text : " + link.text());
			}
			for(Element form:forms)
			{
				System.out.println("form:"+form);
			}*/
		}catch(Exception e)
		{
			e.printStackTrace();
		}
	}
	
	public static void parsingJavaScript(String file)
	{
		
	}

}
